import { Pokemon, PokemonListResponse, PokemonTypeDetails, TypeListResponse } from '../types/pokemon';

/**
 * PokeAPI的基础URL
 * 所有API请求都基于此URL构建
 */
const API_BASE_URL = 'https://pokeapi.co/api/v2';

/**
 * 缓存机制
 * 用于减少重复请求，提高应用性能
 * 包含四种类型的缓存:
 * - pokemonDetails: 基于ID的宝可梦详情缓存
 * - typeDetails: 宝可梦类型详情缓存
 * - pokemonList: 宝可梦列表缓存
 * - urlCache: 基于URL的宝可梦详情缓存
 */
const cache = {
  pokemonDetails: new Map<string, Pokemon>(),
  typeDetails: new Map<number, PokemonTypeDetails>(),
  pokemonList: new Map<string, PokemonListResponse>(),
  urlCache: new Map<string, Pokemon>(), // URL作为键的缓存
};

/**
 * 获取宝可梦列表
 * 支持分页功能，可指定每页数量和偏移量
 *
 * @param limit 每页显示数量，默认20
 * @param offset 偏移量，默认0
 * @returns 返回包含宝可梦基本信息的列表响应
 */
export async function getPokemonList(limit: number = 20, offset: number = 0): Promise<PokemonListResponse> {
  const cacheKey = `list_${limit}_${offset}`;
  
  // 检查缓存是否有数据，有则直接返回
  if (cache.pokemonList.has(cacheKey)) {
    return cache.pokemonList.get(cacheKey)!;
  }
  
  // 发起API请求获取数据
  const response = await fetch(`${API_BASE_URL}/pokemon?limit=${limit}&offset=${offset}`);
  
  // 请求失败处理
  if (!response.ok) {
    throw new Error('Failed to fetch Pokemon list');
  }
  
  // 解析响应数据
  const data = await response.json();
  
  // 将数据存入缓存
  cache.pokemonList.set(cacheKey, data);
  
  return data;
}

/**
 * 获取单个宝可梦的详细信息
 *
 * @param url 宝可梦URL
 * @returns 返回宝可梦的详细信息
 */
export async function getPokemonDetails(url: string): Promise<Pokemon> {
  // 检查缓存
  if (cache.urlCache.has(url)) {
    return cache.urlCache.get(url)!;
  }
  
  // 发起API请求
  const response = await fetch(url);
  
  if (!response.ok) {
    throw new Error(`加载宝可梦详情失败： ${url}`);
  }
  
  const data = await response.json();
  
  // 存入适当的缓存
  cache.urlCache.set(url, data);
  
  return data;
}

/**
 * 批量获取宝可梦详情
 * 实现了请求合并和并发控制，避免同时发送过多请求
 *
 * @param items API返回的{url:string}对象数组
 * @returns 返回宝可梦详情数组
 */
export async function getBatchPokemonDetails(items: (string | number | { url: string })[]): Promise<Pokemon[]> {
  // 处理输入，统一提取URL或ID
  const urls = items.map(item => {
    if (typeof item === 'object' && 'url' in item) {
      return item.url;
    }
    return item;
  });
  
  // 过滤出未缓存的项目，避免重复请求
  const uncachedItems = urls.filter(item => {
    if (typeof item === 'string' && item.startsWith('http')) {
      return !cache.urlCache.has(item);
    }
    return !cache.pokemonDetails.has(item.toString());
  });
  
  // 获取已缓存的宝可梦信息
  const cachedPokemons = urls
    .filter(item => {
      if (typeof item === 'string' && item.startsWith('http')) {
        return cache.urlCache.has(item);
      }
      return cache.pokemonDetails.has(item.toString());
    })
    .map(item => {
      if (typeof item === 'string' && item.startsWith('http')) {
        return cache.urlCache.get(item)!;
      }
      return cache.pokemonDetails.get(item.toString())!;
    });
  
  // 如果全部都已缓存，直接返回缓存数据
  if (uncachedItems.length === 0) {
    return cachedPokemons;
  }
  
  // 分批处理请求，控制并发数量
  const batchSize = 10; // 每批最多10个并发请求
  const batches = [];
  
  // 将请求分成多个批次
  for (let i = 0; i < uncachedItems.length; i += batchSize) {
    const batch = uncachedItems.slice(i, i + batchSize);
    batches.push(batch);
  }
  
  // 依次处理每个批次
  let newPokemons: Pokemon[] = [];
  
  for (const batch of batches) {
    // 并行处理批次内的请求
    const batchPromises = batch.map(url => getPokemonDetails(url.toString()));
    const batchResults = await Promise.all(batchPromises);
    newPokemons = [...newPokemons, ...batchResults];
  }
  
  // 合并缓存和新获取的宝可梦数据
  return [...cachedPokemons, ...newPokemons];
}

/**
 * 获取所有宝可梦类型列表
 *
 * @returns 返回包含所有宝可梦类型的响应
 */
export async function getPokemonTypes(): Promise<TypeListResponse> {
  // 发起API请求
  const response = await fetch(`${API_BASE_URL}/type`);
  
  if (!response.ok) {
    throw new Error('Failed to fetch Pokemon types');
  }
  
  return response.json();
}

/**
 * 获取特定类型的宝可梦列表
 *
 * @param typeId 类型ID
 * @returns 返回指定类型的详细信息，包含该类型的所有宝可梦
 */
export async function getPokemonByType(typeId: number): Promise<PokemonTypeDetails> {
  // 检查缓存
  if (cache.typeDetails.has(typeId)) {
    return cache.typeDetails.get(typeId)!;
  }
  
  // 发起API请求
  const response = await fetch(`${API_BASE_URL}/type/${typeId}`);
  
  if (!response.ok) {
    throw new Error(`Failed to fetch Pokemon for type ${typeId}`);
  }
  
  const data = await response.json();
  
  // 存入缓存
  cache.typeDetails.set(typeId, data);
  
  return data;
}

/**
 * 获取多种类型的宝可梦
 * 查找同时满足所有选中类型的宝可梦
 *
 * @param typeIds 类型ID数组
 * @returns 返回同时具有所有指定类型的宝可梦列表及总数
 */
export async function getPokemonByMultipleTypes(typeIds: number[]): Promise<{ pokemon: { name: string, url: string }[], totalCount: number }> {
  // 处理边界情况：无选中类型
  if (typeIds.length === 0) {
    return { pokemon: [], totalCount: 0 };
  }
  
  // 处理单类型情况：直接使用getPokemonByType
  if (typeIds.length === 1) {
    const result = await getPokemonByType(typeIds[0]);
    return {
      pokemon: result.pokemon.map(p => p.pokemon),
      totalCount: result.pokemon.length
    };
  }
  
  // 多类型情况：需要查找同时满足所有类型的宝可梦
  // 1. 获取每个类型的宝可梦列表
  const typePromises = typeIds.map(typeId => getPokemonByType(typeId));
  const typeResults = await Promise.all(typePromises);
  
  // 2. 使用Map记录每个宝可梦出现在多少种类型中
  const pokemonTypeCountMap = new Map<string, { pokemon: { name: string, url: string }, count: number }>();
  
  // 3. 统计每个宝可梦出现的类型数量
  typeResults.forEach(typeData => {
    typeData.pokemon.forEach(entry => {
      const pokemonName = entry.pokemon.name;
      if (pokemonTypeCountMap.has(pokemonName)) {
        // 已存在，计数加1
        const current = pokemonTypeCountMap.get(pokemonName)!;
        current.count += 1;
      } else {
        // 首次出现，初始计数为1
        pokemonTypeCountMap.set(pokemonName, {
          pokemon: entry.pokemon,
          count: 1
        });
      }
    });
  });
  
  // 4. 筛选出同时满足所有选中类型的宝可梦
  // 只有count等于类型数量的宝可梦才满足条件
  const filteredPokemon = Array.from(pokemonTypeCountMap.values())
    .filter(item => item.count === typeIds.length)
    .map(item => item.pokemon);
  
  return {
    pokemon: filteredPokemon,
    totalCount: filteredPokemon.length
  };
}
